gitlab.com/SiaPrime/SiaPrime@v1.4.1/doc/Running and Writing Tests for SiaPrime.md (about)

     1  # Running and Writing Tests for SiaPrime
     2  Improving test coverage is a great way to start contributing to SiaPrime.  
     3  
     4  This guide focuses on how to write tests. You should also read
     5  [doc/Developers.md][developers] to learn about SiaPrime code conventions and 
     6  quality standards.
     7  
     8  
     9  #### Table of Contents
    10  - [Running and Writing Tests for SiaPrime](#Running-and-Writing-Tests-for-SiaPrime)
    11  			- [Table of Contents](#Table-of-Contents)
    12  	- [Running tests for SiaPrime](#Running-tests-for-SiaPrime)
    13  		- [Updating code before testing](#Updating-code-before-testing)
    14  		- [Testing the entire build](#Testing-the-entire-build)
    15  		- [Testing a particular package or function](#Testing-a-particular-package-or-function)
    16  	- [Writing new tests for SiaPrime](#Writing-new-tests-for-SiaPrime)
    17  		- [A few guidelines](#A-few-guidelines)
    18  		- [Basic test format](#Basic-test-format)
    19  		- [Table-driven tests in Go](#Table-driven-tests-in-Go)
    20  		- [SiaPrimetest Package](#SiaPrimetest-Package)
    21  	- [Questions?](#Questions)
    22  
    23  <a name="existing"></a>
    24  ## Running tests for SiaPrime
    25  Go's comprehensive [test package][pkg/testing] makes testing straightforward,
    26  particularly when you use the bundled tools included in the
    27  [SiaPrime makefile][makefile], including `make test`, `make cover`, `make bench`,
    28  and their variants.
    29  
    30  <a name="update"></a>
    31  ### Updating code before testing
    32  If you just want to run existing tests on the codebase as is, you just need to
    33  pull the latest version of the original repo to your master branch.
    34  
    35  ```bash
    36  # Make sure you are in the right directory.
    37  $ cd $GOPATH/src/github.com/<your Github username>/SiaPrime
    38  # Also make sure you're working with the right branch.
    39  $ git checkout master
    40  # Pull latest changes from origin, the original SiaPrime repo. 
    41  $ git pull origin master
    42  # Update your fork of the repo, which should be set up as a remote.
    43  $ git push <remote>  master
    44  ```
    45  
    46  If you want to run tests on the new code you've added, first make sure the rest
    47  of the code is up to date. New code should be on its own branch.
    48  
    49  ```bash
    50  # Make sure you are in the right directory.
    51  $ cd $GOPATH/src/github.com/<your Github username>/SiaPrime
    52  # Checkout the branch you made the changes on.
    53  $ git checkout <branch name>
    54  # Stash any tracked but uncommitted changes.
    55  $ git stash
    56  # Then switch back to `master` and update it to match the original repo.
    57  $ git checkout master
    58  $ git pull origin master
    59  # Update your fork of the repo, which you should have set up as a remote.
    60  $ git push <remote>  master
    61  # Make the updated `master` the new base of the branch you made the changes on,
    62  # which involves reapplying all the commits made to that branch.  Without the
    63  # `--ignore-date` flag, git rebase changes the date on all the commits to the
    64  # current date.
    65  $ git checkout <branch name>
    66  $ git rebase master --ignore-date
    67  # Restore the changes you stashed earlier.
    68  $ git stash pop
    69  ```
    70  When you call `rebase`, you may run into some merge conflicts.  Luke Champine's
    71  ['How to into git and GitHub'][luke] has more details (and many useful tricks).
    72  
    73  Once the branch you want to test is up to date, you're ready to run some tests.
    74  
    75  <a name="entire"></a>
    76  ### Testing the entire build
    77  The `make test` command runs all tests (functions starting with `Test` in
    78  `_test.go` files) for each package, setting off a panic for any test that runs
    79  longer than 5s.  For verbose output, run `make test-v` (which panics after 15s
    80  instead of 5s).  Finally, `make test-long` has verbose output, only panics when
    81  a test takes 5 minutes, and also cleans up your code using `gofmt` and `golint`. 
    82  **You should run** `make test-long` **before each pull request.**
    83  
    84  Run `make cover` to run all tests for each package and generate color-coded
    85  .html visualizations of test coverage by function for each source file.  Open
    86  `cover/<module>.html` in a browser to inspect a module's test coverage. For 
    87  example, here's part of the html file generated for the persist package: 
    88  
    89  ![Screenshot](assets/covertool.png)
    90  
    91  Meanwhile, `make bench` will call `gofmt` on all packages, then run all
    92  benchmarks (functions starting with `Benchmark` in `_test.go` files).
    93  
    94  <a name="particular"></a>
    95  ### Testing a particular package or function
    96  To run tests for just a certain package, run `make test pkgs=./<package>`. To run 
    97  a certain test function, run `make test pkgs=./<package> run=<function>`. The same
    98  goes for `make test-long`, `make cover` and `make bench`.
    99  
   100  For example, running `test-long` on the package persist produces this output:
   101  
   102  ```bash
   103  $ make test-long pkgs=./persist
   104  rm -rf release doc/whitepaper.aux doc/whitepaper.log doc/whitepaper.pdf
   105  gofmt -s -l -w ./persist
   106  go install ./persist
   107  go vet ./persist
   108  go test -v -race -tags='testing debug' -timeout=300s ./persist -run=Test
   109  === RUN   TestOpenDatabase
   110  --- PASS: TestOpenDatabase (0.42s)
   111  === RUN   TestSaveLoad
   112  --- PASS: TestSaveLoad (0.00s)
   113  === RUN   TestSaveLoadFile
   114  --- PASS: TestSaveLoadFile (0.01s)
   115  === RUN   TestSaveLoadFileSync
   116  --- PASS: TestSaveLoadFileSync (0.00s)
   117  === RUN   TestLogger
   118  --- PASS: TestLogger (0.00s)
   119  === RUN   TestLoggerCritical
   120  --- PASS: TestLoggerCritical (0.00s)
   121  === RUN   TestIntegrationRandomSuffix
   122  --- PASS: TestIntegrationRandomSuffix (0.01s)
   123  === RUN   TestAbsolutePathSafeFile
   124  --- PASS: TestAbsolutePathSafeFile (0.00s)
   125  === RUN   TestRelativePathSafeFile
   126  --- PASS: TestRelativePathSafeFile (0.00s)
   127  PASS
   128  ok  	gitlab.com/SiaPrime/SiaPrime/persist	1.485s
   129  $
   130  ``` 
   131  
   132  <a name="write"></a>
   133  ## Writing new tests for SiaPrime
   134  When you run `make cover`, you'll notice that many files have pretty low
   135  coverage.  We're working on fixing that, but we could use your help.
   136  
   137  <a name="naming"></a>
   138  ### A few guidelines
   139  * The test functions for `filename.go` should go in `filename_test.go` in the
   140      same directory and package.
   141  * A test function name should start with `Test` and clearly convey what is
   142      being tested.
   143  * You should declare function-specific variables and constants locally (inside
   144      the test function) instead of globally (outside the test function).  [That 
   145  	holds in general][global], not just for tests.
   146  * As always, code should adhere to the standards and conventions laid out in
   147      [doc/Developers.md][developers].
   148  * If a test interacts with the disk it should be skipped during the short tests
   149    by including the following at the beginning of the test:
   150    ```go
   151    if testing.Short() {
   152  	  t.SkipNow()
   153    }
   154    ```
   155  
   156  <a name="basic"></a>
   157  ### Basic test format
   158  Suppose we'd like to test the Bar method belonging to type Foo.  
   159  
   160  ```go
   161  // TestFoo checks that the Bar method on type Foo responds correctly to a normal
   162  // input and returns the expected error when given a bad input.
   163  func TestFoo(t *testing.T) {
   164  	foo, err := NewFoo()
   165  	if err != nil {
   166  	// If NewFoo failed, we can't continue testing.
   167  	t.Fatal(err)
   168  	}
   169  
   170  	// Try a normal input; should succeed.
   171  	err := foo.Bar(3)
   172  	if err != nil {
   173  		// Report the error, but don't abort the test.
   174  		t.Error(err)
   175  	}
   176  
   177  	// Try a bad input; should return an error.
   178  	// NOTE: Always prefer to compare to a specific error, rather than 
   179  	// err == nil
   180  	err = Foo.Bar(0)
   181  	if err != errDivideByZero {
   182  		t.Errorf("expected errDivideByZero, got %v", err)
   183  	}
   184  }
   185  
   186  ```
   187  
   188  <a name="table"></a>
   189  ### Table-driven tests in Go
   190  If you're looking to test a bunch of inputs, write a [table-driven test][table]
   191  with a slice of anonymous structs. For example, see `TestParseFileSize` in 
   192  [spc/parse_test.go][parse_test]:
   193  
   194  ```go
   195  func TestParseFilesize(t *testing.T) {
   196  	// Define a table of test cases in the form of a slice of anonymous structs.
   197  	tests := []struct {
   198  		in, out string
   199  		err     error
   200  	}{
   201  		{"1b", "1", nil},
   202  		{"1KB", "1000", nil},
   203  		{"1MB", "1000000", nil},
   204  		{"1GB", "1000000000", nil},
   205  		{"1TB", "1000000000000", nil},
   206  		{"1KiB", "1024", nil},
   207  		{"1MiB", "1048576", nil},
   208  		{"1GiB", "1073741824", nil},
   209  		{"1TiB", "1099511627776", nil},
   210  		{"", "", errUnableToParseSize},
   211  		{"123", "123", nil},
   212  		{"123TB", "123000000000000", nil},
   213  		{"123GiB", "132070244352", nil},
   214  		{"123BiB", "", errUnableToParseSize},
   215  		{"GB", "", errUnableToParseSize},
   216  		{"123G", "", errUnableToParseSize},
   217  		{"123B99", "", errUnableToParseSize},
   218  		{"12A3456", "", errUnableToParseSize},
   219  		{"1.23KB", "1230", nil},
   220  		{"1.234KB", "1234", nil},
   221  		{"1.2345KB", "1234", nil},
   222  	}
   223  	// Loop through the table of test cases to make sure ParseFileSize returns 
   224  	// the expected output and error for each.
   225  	for _, test := range tests {
   226  		res, err := parseFilesize(test.in)
   227  		if res != test.out || err != test.err {
   228  			t.Errorf("parseFilesize(%v): expected %v %v, got %v %v", test.in, test.out, test.err, res, err)
   229  		}
   230  	}
   231  }
   232  ```
   233  
   234  <a name="siaPrimetest">
   235  ### SiaPrimetest Package
   236  When deciding what tests to write for SiaPrime, you should consider whether the 
   237  best test is a unit test or a siaprimetest. Ideally both a unit test and a 
   238  siaprimetest is written for new code. A unit test should explicitly test the new
   239  code functionality and a siaprimetest should test the integration of the code 
   240  and how itaffects the rest of the platform. All the tests in the siaprimetest
   241  package should use the API to execute the test. The idea is that everything that
   242  is trying to be tested should be able to be controlled and verified through the 
   243  API. If you are looking for a place to start, there are many examples of older 
   244  tests that could be upgraded to siaprimetests.
   245  
   246  <a name="questions"></a>
   247  ## Questions?
   248  Read these if you haven't already:
   249  * getting started with Go 
   250  * SiaPrime, and git
   251  * [doc/Developers.md][developers]: conventions and quality standards for 
   252  * SiaPrime code
   253  
   254  Some other useful resources, some of which have been linked to already:
   255  * [Golang.org page on the go testing package][pkg/testing]
   256  * [Writing Table-Driven Tests in Go][table]
   257  * [How to Write Benchmarks in Go][cheney-benchmarks]
   258  * [How to into git and GitHub][luke]: an essential introduction to git
   259  
   260  And feel free to ask questions on the [#development channel][discord] on the 
   261  SiaPrime Discord. 
   262  Odds are, someone else is wondering the same thing.
   263  
   264  [pkg/testing]: https://golang.org/pkg/testing/
   265  [makefile]: https://gitlab.com/SiaPrime/SiaPrime/blob/master/Makefile
   266  [luke]: https://gist.github.com/lukechampine/6418449
   267  [developers]: https://gitlab.com/SiaPrime/SiaPrime/blob/master/doc/Developers.md
   268  [table]: http://dave.cheney.net/2013/06/09/writing-table-driven-tests-in-go
   269  [boltdb_test.go]: https://gitlab.com/SiaPrime/SiaPrime/blob/master/persist/boltdb_test.go
   270  [cheney-benchmarks]: http://dave.cheney.net/2013/06/30/how-to-write-benchmarks-in-go
   271  [pkg/testing]: https://golang.org/pkg/testing/
   272  [discord]: https://discord.gg/5DAgTn8
   273  [parse_test]: https://gitlab.com/SiaPrime/SiaPrime/blob/master/spc/parse_test.go
   274  [global]: http://c2.com/cgi/wiki?GlobalVariablesAreBad